package es.uoc.mxpdroid.ihm;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.Vibrator;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;

import org.osmdroid.api.IMapView;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapController;
import org.osmdroid.views.MapView;
import org.osmdroid.views.MapView.Projection;
import org.osmdroid.DefaultResourceProxyImpl;
import org.osmdroid.ResourceProxy;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.Drawable;


import org.osmdroid.views.overlay.ItemizedIconOverlay;
import org.osmdroid.views.overlay.ItemizedOverlay;
import org.osmdroid.views.overlay.MinimapOverlay;
import org.osmdroid.views.overlay.MyLocationOverlay;
import org.osmdroid.views.overlay.OverlayItem;
import org.osmdroid.views.overlay.OverlayItem.HotspotPlace;
import org.osmdroid.views.overlay.ScaleBarOverlay;
import org.osmdroid.views.overlay.PathOverlay;

import com.example.mxpdroid.R;

import es.uoc.mxpdroid.algorithm.AccCostAlgorithm;
import es.uoc.mxpdroid.algorithm.AccCostAnisotropicAlgorithm;
import es.uoc.mxpdroid.algorithm.AspectAlgorithm;
import es.uoc.mxpdroid.algorithm.CombineGridsAlgorithm;
import es.uoc.mxpdroid.algorithm.CombineMaskAlgorithm;
import es.uoc.mxpdroid.algorithm.LeastCostPathAlgorithm;
import es.uoc.mxpdroid.algorithm.ReclassifyAlgorithm;
import es.uoc.mxpdroid.algorithm.SlopeAlgorithm;
import es.uoc.mxpdroid.entity.RasterLayer;
import es.uoc.mxpdroid.entity.XpGeoPoint;
import es.uoc.mxpdroid.util.GeoUTM;
import es.uoc.mxpdroid.util.Logger;
import es.uoc.mxpdroid.util.ReadPonderFile;
import es.uoc.mxpdroid.util.ReadReclassFile;


public class MainActivity extends Activity  {
	
	// Layout controllers
	private MapView myMapView;
	private MapController myMapController;
	private MyLocationOverlay myLocation;
	private LocationManager locatManager;
	private ArrayList<OverlayItem> overlayLocArray;
	private ArrayList<OverlayItem> overlayPoiArray;
	
	// Parameters and local default settings
	private boolean isCalculating 	= 	false;
	private double factorK 			= 	2.0;
	private int distMethod			=	AccCostAlgorithm.EUCLIDEAN; //Euclidian distance
	
	// Parameters from SD memory
	private boolean sdAvailable 	= 	false;
	private boolean sdWriteAcces 	= 	false;
	
	//Path and static names
	private String 	path_root		= 	"/mnt/ext_card/mXPdroid/";
	private String	path_accCost	=	"/mnt/ext_card/mXPdroid/accCost/";
	private String	path_dtm 		=	"/mnt/ext_card/mXPdroid/mdt/";
    private String[] staticLayers	=	{"unitaryCost_30x30.asc", "aspect_30x30.asc"};
	
	private RasterLayer accCost;
	
	private ArrayList<String[]> m_POIS;
	
	// touched and GPS latitude/longitude position
	private double touchLat			=	0.0;
	private double touchLon			=	0.0;
	private double gpsLat			=	0.0;
	private double gpsLon			=	0.0;
	private float totalDist			= 	0;
	private double[][] utmZone;
	
	// parameter to do calculations of AccCost and LCP
	private double lat, lon;
	private String name_POI;
	private boolean isAnisotropic;
	private int replaceTo;
	private ArrayList<XpGeoPoint> path;
	
	// identifiers on Sub-Activities
	private static final int ACT_SETTINGS			=	0;
	private static final int ACT_POI				=	1;
	private static final int ACT_ORIG				=	2;
	private static final int ACT_LIST				=	3;
	
	// necessary to lock screen with Map
	private WakeLock wakeLock;
	
	
	// To show what is in process at the moment
	TextView infoText;
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		
		//verification for SD
		testMem();
		initCostLayerList();
		(new Logger()).erase();
		accCost = null;
		//readOneLayer();
		
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		//this allow to keep app up (not to lock screen)
		PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
		wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "My Lock");
		
		myMapView = (MapView)findViewById(R.id.openmapview);
		myMapView.setBuiltInZoomControls(true);
		myMapController = myMapView.getController();
		myMapController.setCenter(new GeoPoint(42.5, 2.0));
		myMapController.setZoom(9);
		
		
		//compas is Overlay n°0
		myLocation = new MyLocationOverlay(this, myMapView);
		myMapView.getOverlays().add(0, myLocation);
		myLocation.runOnFirstFix(new Runnable(){
			public void run(){
				myMapView.getController().animateTo(myLocation.getMyLocation());
			}
		});
		myLocation.setCompassCenter(30, 25);
		
		
		//GPS localization
		locatManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
		Location lastLoc = locatManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
		if (lastLoc != null){
			//updateLoc(lastLoc);
		}
		
		// Create Overlay with LOC GPS or NETWORK -- Overlay n°1
		// and add it to the map this overlay allow to get TAP position too
        overlayLocArray = new ArrayList<OverlayItem>();
        DefaultResourceProxyImpl defaultResourceProxyImpl = new DefaultResourceProxyImpl(this);
        MyLocIconOverlay myItemizedIconOverlay = new MyLocIconOverlay(
           overlayLocArray, null, defaultResourceProxyImpl);
        myMapView.getOverlays().add(1, myItemizedIconOverlay);
        //---
        
        // Create Overlay with POIs -- Overlay n°2
        overlayPoiArray = new ArrayList<OverlayItem>();
//        for(int ii = 0; ii < m_POIS.size(); ii++){
//        	double[] xyUTM = {Double.parseDouble(m_POIS.get(ii)[3]), Double.parseDouble(m_POIS.get(ii)[4])};
//        	double[] geo = (new GeoUTM(GeoUTM.ETRS89)).passToGeographic(xyUTM[0], xyUTM[1], 31, false, true);
//        	geo = new GeoUTM().changeEllip(geo, GeoUTM.ETRS89, GeoUTM.WGS84);
//        	(new Logger()).writeLog(m_POIS.get(ii)[1] + "\t" + Double.toString(geo[0]) + "\t" + Double.toString(geo[1]));
//        	GeoPoint endPoint = new GeoPoint( (int)(geo[0] * 1e6), (int)(geo[1] * 1e6));
//        	OverlayItem newMyLocationItem = new OverlayItem(
//        		       m_POIS.get(ii)[1],  m_POIS.get(ii)[1], endPoint);
//        	Drawable newMarker = getApplicationContext().getResources().getDrawable(R.drawable.destination_point);
//			newMyLocationItem.setMarker(newMarker);
//			newMyLocationItem.setMarkerHotspot(HotspotPlace.CENTER);
//        	overlayPoiArray.add(newMyLocationItem);
//        }
        initPOIOverlay();
        ItemizedIconOverlay<OverlayItem> myPoisIconOverlay =  new ItemizedIconOverlay<OverlayItem>(
                overlayPoiArray, null, defaultResourceProxyImpl);
        myMapView.getOverlays().add(2, myPoisIconOverlay);
        myMapView.invalidate();
		
		//mesura del mapa (Scale bar) -- Overlay n°3
		ScaleBarOverlay myScale = new ScaleBarOverlay(this);
		myMapView.getOverlays().add(3, myScale);
		myScale.setScaleBarOffset(60, 15);
		
		infoText = (TextView)findViewById(R.id.textView1);
		infoText.setText("Waiting");
		
		//Region with data -- Overlay n°4
		PathOverlay dataZone = new PathOverlay(Color.YELLOW, this);
		utmZone = new double[4][2];
		utmZone[0][0] = 374332.5;
		utmZone[0][1] = 4687957.5;
		utmZone[2][0] = 402217.5;
		utmZone[2][1] = 4668922.5;
		utmZone[1][0] = 402217.5;
		utmZone[1][1] = 4687957.5;
		utmZone[3][0] = 374332.5;
		utmZone[3][1] = 4668922.5;
		for(int ii=0; ii < utmZone.length; ii++){
			utmZone[ii] = (new GeoUTM(GeoUTM.ETRS89)).passToGeographic(utmZone[ii], 31, false, true);
			dataZone.addPoint(new GeoPoint( (int)(utmZone[ii][0] * 1e6),
					(int)(utmZone[ii][1] * 1e6) ) );
		}
		dataZone.addPoint(new GeoPoint( (int)(utmZone[0][0] * 1e6), (int)(utmZone[0][1] * 1e6) ));
		myMapView.getOverlays().add(4, dataZone);
	}
	
	private void initPOIOverlay(){
		overlayPoiArray.clear();
		for(int ii = 0; ii < m_POIS.size(); ii++){
        	double[] xyUTM = {Double.parseDouble(m_POIS.get(ii)[3]), Double.parseDouble(m_POIS.get(ii)[4])};
        	double[] geo = (new GeoUTM(GeoUTM.ETRS89)).passToGeographic(xyUTM[0], xyUTM[1], 31, false, true);
        	geo = new GeoUTM().changeEllip(geo, GeoUTM.ETRS89, GeoUTM.WGS84);
        	GeoPoint endPoint = new GeoPoint( (int)(geo[0] * 1e6), (int)(geo[1] * 1e6));
        	OverlayItem newMyLocationItem = new OverlayItem(
        		       m_POIS.get(ii)[1],  m_POIS.get(ii)[1], endPoint);
        	Drawable newMarker = getApplicationContext().getResources().getDrawable(R.drawable.destination_point);
			newMyLocationItem.setMarker(newMarker);
			newMyLocationItem.setMarkerHotspot(HotspotPlace.CENTER);
        	overlayPoiArray.add(newMyLocationItem);
        }
	}
	
	/**
	 * This function verifies that a given point is inside the zone
	 * @param test
	 * @return
	 */
	private boolean pointInside(double[] test){
		int ii, jj;
		boolean result = false;
		for(ii = 0, jj = utmZone.length - 1; ii < utmZone.length; jj = ii++)
			if ( (utmZone[ii][1] > test[1]) != (utmZone[jj][1] > test[1]) &&
					(test[0] < (utmZone[jj][0] - utmZone[ii][0]) * (test[1] - utmZone[ii][1]) 
					      / (utmZone[jj][1] - utmZone[ii][1]) + utmZone[ii][0] ))
				result = !result;
		
		return result;
	}
	
	private void initCostLayerList(){
		m_POIS = new ArrayList<String []>();
		String[] tmp;
		StringTokenizer stk;
		int ii;
		
		File ff = new File (path_root, "listAccCost.txt");
		try{
			FileReader fr = new FileReader(ff);
			BufferedReader br = new BufferedReader(fr);
			
			if (br.ready()) br.readLine(); //first line is a comment line
			else{
				br.close();
				fr.close();
				return;
			}
			while(br.ready()){
				stk = new StringTokenizer(br.readLine(), ";");
				tmp = new String[stk.countTokens()];
				ii = 0;
				while(stk.hasMoreTokens()){
					tmp[ii] = stk.nextToken();
					ii++;
				}
				m_POIS.add(tmp);
			}
			br.close();
			fr.close();
		}catch(Exception e){e.printStackTrace();}
	}	
	
//	private void readOneLayer(){
//		accCost = new RasterLayer(RasterLayer.ICC);
//		Toast.makeText(getApplicationContext(), "OK 1", Toast.LENGTH_LONG).show();
//		accCost.initFromFile(m_POIS.get(0)[2], new File(path_accCost));
//		Toast.makeText(getApplicationContext(), "OK 2", Toast.LENGTH_LONG).show();
//	}
	
	/**
	 * This function evaluates the state of the external memory
	 * SD card needs to be configured to have DEM data and path hierarchy 
	 */
	private void testMem(){
		//verify if SD is well mounted
				String memState = Environment.getExternalStorageState();
				if (memState.equals(Environment.MEDIA_MOUNTED)){
					sdAvailable = true;
					sdWriteAcces = true;
				}
				else if (memState.equals(Environment.MEDIA_MOUNTED_READ_ONLY)){
					sdAvailable = true;
					sdWriteAcces = false;
				}
				else{
					sdAvailable = false;
					sdWriteAcces = false;
				}
				if (sdAvailable){
					File ff = new File(path_root);
					File ff_accCost = new File(ff.getAbsoluteFile() + File.separator + "accCost");
					File ff_mdt = new File(ff.getAbsoluteFile() + File.separator + "mdt");
					//if general path does not exist or mdt data not exist
					if(!ff.exists() || !ff_mdt.exists()){
						//defining alert message
						AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
						alertDialog.setTitle("WARNING");
						alertDialog.setMessage("DTM data is missing! Impossible to calculate LCP")
						.setCancelable(false)
						.setPositiveButton("OK", new DialogInterface.OnClickListener() {
							
							@Override
							public void onClick(DialogInterface arg0, int arg1) {
								// TODO Auto-generated method stub
								//MainActivity.this.finish();
								arg0.cancel();
							}
						});
						alertDialog.show();
					} //end if mdt data not exist
					
					else if (!sdWriteAcces){
						//defining alert message
						AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
						alertDialog.setTitle("WARNING");
						alertDialog.setMessage("Write acces no allowed! New LCP ")
						.setCancelable(false)
						.setPositiveButton("OK", new DialogInterface.OnClickListener() {
							
							@Override
							public void onClick(DialogInterface arg0, int arg1) {
								// TODO Auto-generated method stub
								arg0.cancel();
							}
						});
						alertDialog.show();
					} //end if writeAcces problem
				}
				//end if SD available
				else{
					//defining alert message
					AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
					alertDialog.setTitle("FATAL ERROR");
					alertDialog.setMessage("SD card is missing, any DTM data can be load!")
					.setCancelable(false)
					.setPositiveButton("OK", new DialogInterface.OnClickListener() {
						
						@Override
						public void onClick(DialogInterface arg0, int arg1) {
							// TODO Auto-generated method stub
							MainActivity.this.finish();
						}
					});
					alertDialog.show();
					
				}
	}

	@Override
	protected void onResume(){
		super.onResume();
		myLocation.enableMyLocation();
		myLocation.enableCompass();
		locatManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, myLocationListener);
		locatManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, myLocationListener);
		wakeLock.acquire();
		
	}
	
	@Override
	protected void onPause(){
		super.onPause();
		myLocation.disableMyLocation();
		myLocation.disableCompass();
		locatManager.removeUpdates(myLocationListener);
		wakeLock.release();
	}
	
	/**
	 * Update the localization of the user
	 * @param loc
	 */
	private void updateLoc(Location loc){
		 gpsLat = loc.getLatitude();
	     gpsLon = loc.getLongitude();
	     GeoPoint locGeoPoint = new GeoPoint(gpsLat, gpsLon);
	     myMapController.setCenter(locGeoPoint);
	     //setOverlayLoc(loc);
	     myMapView.invalidate();
	 }
	 
	/**
	 * Superposition of the localization GPS
	 * @param overlayloc
	 */
	 private void setOverlayLoc(Location overlayloc){
	  GeoPoint overlocGeoPoint = new GeoPoint(overlayloc);
	  //---
	     overlayLocArray.clear();
	     OverlayItem newMyLocationItem = new OverlayItem(
	       "My Location GPS", "My Location GPS", overlocGeoPoint);
	     overlayLocArray.add(newMyLocationItem);
	     //---
	 }
	
	 // this class allow to listen location changes and update the location point on the map
	 private LocationListener myLocationListener
	 = new LocationListener(){

		  @Override
		  public void onLocationChanged(Location location) {
		   // TODO Auto-generated method stub
		   updateLoc(location);
		  }
		
		  @Override
		  public void onProviderDisabled(String provider) {
		   // TODO Auto-generated method stub
		   
		  }
		
		  @Override
		  public void onProviderEnabled(String provider) {
		   // TODO Auto-generated method stub
		   
		  }
		
		  @Override
		  public void onStatusChanged(String provider, int status, Bundle extras) {
		   // TODO Auto-generated method stub
		   
		  }
     
    };
	
    /**
     * This class is for plotting POIs in the MAP on the specific Overlay
     * @author sergio
     *
     */
    
    // this Overlay allow to plot the location GPS marker on the map
    // but we use it too to get the lat/lon position when singleTouch by user
    private class MyLocIconOverlay extends ItemizedIconOverlay<OverlayItem>{

    	  public MyLocIconOverlay(
    	    List<OverlayItem> pList,
    	    org.osmdroid.views.overlay.ItemizedIconOverlay.OnItemGestureListener<OverlayItem> pOnItemGestureListener,
    	    ResourceProxy pResourceProxy) {
    	   super(pList, pOnItemGestureListener, pResourceProxy);
    	   // TODO Auto-generated constructor stub
    	  }

    	  @Override
    	  public void draw(Canvas canvas, MapView mapview, boolean arg2) {
    	   // TODO Auto-generated method stub
    	   super.draw(canvas, mapview, arg2);
    	   if(!overlayLocArray.isEmpty()){
    		    
    		    GeoPoint in = overlayLocArray.get(0).getPoint();
    		    
    		    Point out = new Point();
    		    mapview.getProjection().toPixels(in, out);
    		    
    		    Bitmap bm = BitmapFactory.decodeResource(getResources(), 
    		      R.drawable.start_point);
    		    canvas.drawBitmap(bm, 
    		      out.x - bm.getWidth()/2,  //shift the bitmap center
    		      out.y - bm.getHeight()/2,  //shift the bitmap center
    		      null);
    		}
    	}

    	@Override
    	public boolean onSingleTapConfirmed(MotionEvent ev, MapView mapView) {
    		   // TODO Auto-generated method stub
    		Projection proj = mapView.getProjection();
			GeoPoint loc = (GeoPoint) proj.fromPixels((int)ev.getX(), (int)ev.getY());
			double[] tmp = new double[2];
			tmp[0] = (double)loc.getLatitudeE6() / 1e6;
			tmp[1] = (double)loc.getLongitudeE6() / 1e6;
			//tmp = (new GeoUTM(GeoUTM.WGS84)).passToUTM(tmp[0], tmp[1], 31);
			if (pointInside(tmp)){
				touchLon = (double)loc.getLongitudeE6() / 1e6;
				touchLat = (double)loc.getLatitudeE6() / 1e6;
				final String longitude = Double.toString(touchLon);
				final String latitude = Double.toString(touchLat);
				Toast tt = Toast.makeText(getApplicationContext(), "New Point Saved:\nLongitude: " + longitude + 
						"\nLatitude: "+latitude, Toast.LENGTH_LONG);
				tt.show();
			}
			else{
				Toast tt = Toast.makeText(getApplicationContext(), "Point is outside Zone!! Try again" , Toast.LENGTH_LONG);
				tt.show();
				ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
				toneG.startTone(ToneGenerator.TONE_SUP_CONGESTION_ABBREV, 200);
			}
    		return true;
    	}
    } //end myItemIconOverlay
    
	
	
    //This class allow to do a new calculation of AccSurf from à new Point
    private class MyCalcNewAccCost extends AsyncTask<Void, Integer, Boolean>{
    	@Override
		protected void onPreExecute(){
			if (isCalculating){
				Toast.makeText(getApplicationContext(), "Other task in progress... Try later!", Toast.LENGTH_LONG).show();
			}
			else
				Toast.makeText(getApplicationContext(), "Processing New AccCost Surface...", Toast.LENGTH_LONG).show();
		}
    	
		@Override
		protected Boolean doInBackground(Void... arg0) {
			if (!isCalculating){
				isCalculating = true;
				//Loading UnitaryCost 30x30
				(new Logger()).writeLog("PROC ==> Loading Unitary Cost 30x30 <== ");
				long startTime = System.currentTimeMillis();
				RasterLayer uCost = new RasterLayer(RasterLayer.ICC30);
				uCost.initFromFile(staticLayers[0], new File(path_dtm));
				long endTime = System.currentTimeMillis();
				(new Logger()).writeLog("PROC_TIME ==> Unitary Cost 30x30 loaded in: " + Long.toString(endTime-startTime) + " ms");
				//Loading AspectSurfca 30x30
				(new Logger()).writeLog("PROC ==> Loading Aspect 30x30 <==");
				startTime = System.currentTimeMillis();
				RasterLayer aspect = new RasterLayer(RasterLayer.ICC30);
				aspect.initFromFile(staticLayers[1], new File(path_dtm));
				endTime = System.currentTimeMillis();
				(new Logger()).writeLog("PROC_TIME ==> Aspect 30x30 loaded in: " + Long.toString(endTime-startTime) + " ms");
				
				//Creating POI surface
				(new Logger()).writeLog("PROC ==> Creating POI Surface <==");
				startTime = System.currentTimeMillis();
				RasterLayer pp = new RasterLayer(RasterLayer.ICC30);
		        pp.initFromLayer(uCost);
		        //set data at current ii POI
		        pp.setDataAtLatLon(lat, lon, 100);
		        endTime = System.currentTimeMillis();
				(new Logger()).writeLog("PROC_TIME ==> Aspect 30x30 loaded in: " + Long.toString(endTime-startTime) + " ms");
				
		        
		        if(isAnisotropic){
		        	(new Logger()).writeLog("PROC ==> Start calc Anisotropic AccCost 30x30 <==");
		        	startTime = System.currentTimeMillis();
//		        	accCost = new AccCostAnisotropicAlgorithm(uCost, aspect, pp, factorK).getResultLayer();
		        	accCost = new AccCostAnisotropicAlgorithm(uCost, aspect, lat, lon, factorK).getResultLayer();
		        	endTime = System.currentTimeMillis();
					(new Logger()).writeLog("PROC_TIME ==> End calc Anisotropic AccCost in: " + Long.toString(endTime-startTime) + " ms");
		        }
		        else{
		        	(new Logger()).writeLog("PROC ==> Start calc Isotropic AccCost 30x30 <==");
		        	startTime = System.currentTimeMillis();
		        	accCost = new AccCostAlgorithm(uCost, pp, distMethod).getResultLayer();
		        	endTime = System.currentTimeMillis();
					(new Logger()).writeLog("PROC_TIME ==> End calc Anisotropic AccCost in: " + Long.toString(endTime-startTime) + " ms");
		        }
		        
		        //write new surface on the list and update the file with new data
		        double[] xy_UTM = (new GeoUTM(GeoUTM.WGS84)).passToUTM(lat, lon, 31);
		        m_POIS.get(replaceTo - 1)[1] = name_POI;
		        m_POIS.get(replaceTo - 1)[3] = Integer.toString((int)xy_UTM[0]);
		        m_POIS.get(replaceTo - 1)[4] = Integer.toString((int)xy_UTM[1]);
		        m_POIS.get(replaceTo - 1)[5] = Boolean.toString(isAnisotropic);
		        
		        //update infoFile
		        File ff = new File (path_root, "listAccCost.txt");
				try{
					FileWriter fw = new FileWriter(ff);
					BufferedWriter bw = new BufferedWriter(fw);
					
					//write first line of head
					bw.write("ID;POI_name;Path;x_UTM;y_UTM;isAnisotropic\n");
					
					for(int ii = 0; ii< m_POIS.size(); ii ++){
						int jj;
						for(jj = 0; jj < m_POIS.get(ii).length - 1; jj ++){
							bw.write(m_POIS.get(ii)[jj] + ";");
						}
						bw.write(m_POIS.get(ii)[jj] + "\n");
					}
					
					bw.close();
					fw.close();
					(new Logger()).writeLog("INFO ==> List file updated");
				}catch(Exception e){e.printStackTrace();
				(new Logger()).writeLog("ERROR ==> Problem during list file updating");}
				
				//update the AccCostSurface file
				ff = new File (path_accCost, "surface" + m_POIS.get(replaceTo-1)[0] + ".asc");
				try{
			        accCost.printToAsciiFile(ff);
			        (new Logger()).writeLog("INFO ==> AccCost surface file updated");
				}catch(Exception e){e.printStackTrace();
				(new Logger()).writeLog("ERROR ==> Problem during AccCost surface file updating");}
				
				isCalculating = false;
				return true;
			}
			return false;
		}
		
		@Override
		protected void onPostExecute(Boolean result){
			if(result){
				initPOIOverlay();
				DefaultResourceProxyImpl defaultResourceProxyImpl = new DefaultResourceProxyImpl(getApplicationContext());
				ItemizedIconOverlay<OverlayItem> myPoisIconOverlay =  new ItemizedIconOverlay<OverlayItem>(
			                overlayPoiArray, null, defaultResourceProxyImpl);
			    myMapView.getOverlays().set(2, myPoisIconOverlay);
				myMapView.invalidate();
				Toast.makeText(getApplicationContext(), 
						"New AccCost for " + name_POI + " available!", Toast.LENGTH_LONG).show();
				ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
				toneG.startTone(ToneGenerator.TONE_SUP_CONGESTION_ABBREV, 200);
				Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);  
			    vib.vibrate(200);
			}
		}
    }
    
    
	//Asynchronous class task to do the calculation
	private class MyCalcLCP extends AsyncTask<Void, Integer, Boolean>{
		@Override
		protected void onPreExecute(){
			if (isCalculating){
				Toast.makeText(getApplicationContext(), "In progress... Try later!", Toast.LENGTH_LONG).show();
			}
			else if (accCost == null)
				Toast.makeText(getApplicationContext(), "YOU NEED TO CHOOSE A POI!", Toast.LENGTH_LONG).show();
			else
				Toast.makeText(getApplicationContext(), "Processing Least-Cost Path...", Toast.LENGTH_LONG).show();
		}
		
		@Override
		protected void onPostExecute(Boolean result){
			if(result){
				Toast.makeText(getApplicationContext(), "New Path available!", Toast.LENGTH_LONG).show();
				Toast.makeText(getApplicationContext(), "Total distance is: " + totalDist + " km", Toast.LENGTH_LONG).show();
				ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
				toneG.startTone(ToneGenerator.TONE_SUP_CONGESTION_ABBREV, 200);
				Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);  
			    vib.vibrate(200);
				
				PathOverlay lcpFinal = new PathOverlay(Color.RED, getApplicationContext());
				for(int ii = 0; ii< path.size(); ii++){
					lcpFinal.addPoint(new GeoPoint( path.get(ii).getMicroLatitude(), path.get(ii).getMicroLongitude() ));
				}
				//Overlay Path is n°6
				if(myMapView.getOverlays().size() > 5)
					myMapView.getOverlays().remove(5);
				myMapView.getOverlays().add(5, lcpFinal);
				
				//Plot start point -- Overlay n°7
				if( myMapView.getOverlays().size() > 6)
					myMapView.getOverlays().remove(6);
				GeoPoint start = new GeoPoint( path.get(0).getMicroLatitude(), path.get(0).getMicroLongitude() );
				OverlayItem olItem = new OverlayItem("Start", "Start Point", start);
				Drawable newMarker = getApplicationContext().getResources().getDrawable(R.drawable.start_point);
				olItem.setMarker(newMarker);
				olItem.setMarkerHotspot(HotspotPlace.CENTER);
				ArrayList<OverlayItem> tmp = new ArrayList<OverlayItem>();
				tmp.add(olItem);
		        DefaultResourceProxyImpl defaultResourceProxyImpl = new DefaultResourceProxyImpl(getApplicationContext());
				ItemizedIconOverlay<OverlayItem> myPoisIconOverlay =  new ItemizedIconOverlay<OverlayItem>(
						tmp, null, defaultResourceProxyImpl);
		        myMapView.getOverlays().add(6, myPoisIconOverlay);
		        
				myMapView.invalidate();
				
			}
			
		}
		
		@Override
		protected Boolean doInBackground(Void... arg0) {
			// TODO Auto-generated method stub
			if (!isCalculating && accCost != null){
				isCalculating = true;
				try {
					XpGeoPoint gp = new XpGeoPoint(lat, lon);
					(new Logger()).writeLog("INFO ==> LCP for Latitude: " + Double.toString(lat) + " and Longitud: " + Double.toString(lon));
					long startTime = System.currentTimeMillis();
					(new Logger()).writeLog("PROC ==> Starting LCP calculation <==");
					LeastCostPathAlgorithm lcpa = new LeastCostPathAlgorithm(accCost, gp);
					long endTime = System.currentTimeMillis();
					endTime -= startTime;
					(new Logger()).writeLog("INFO ==> LCP calculation Finished with total lenght of: " + Integer.toString(lcpa.getPath().size()));
					(new Logger()).writeLog("PROC_TIME ==>End LCP Proccess in: " + Long.toString(endTime) + " ms");
					path = lcpa.getPath();
					totalDist = lcpa.totalDistance();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					(new Logger()).writeLog( "ERROR ==> Problem occures in LCP algorithm!");
					e.printStackTrace();
				}
				isCalculating = false;
				return true;
			}
			return false;
		}
		
		@Override
		protected void onCancelled(){
			try {
				
			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	} //end my AsyncTask
	
	//Asynchronous class task to do the calculation
		private class MyLoadAccCost extends AsyncTask<Void, Integer, Boolean>{
			@Override
			protected void onPreExecute(){
				if (isCalculating)
					Toast.makeText(getApplicationContext(), "In progress... Try later!", Toast.LENGTH_LONG).show();
				else
					Toast.makeText(getApplicationContext(), "Loading AccCost Surface...", Toast.LENGTH_LONG).show();
			}
			
			@Override
			protected void onPostExecute(Boolean result){
				if(result){
					Toast.makeText(getApplicationContext(), "New AccCost Surface loaded!", Toast.LENGTH_LONG).show();
					ToneGenerator toneG = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 50);
					toneG.startTone(ToneGenerator.TONE_CDMA_ALERT_CALL_GUARD, 200);
					Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);  
				    vib.vibrate(200);
				}
			}
			
			@Override
			protected Boolean doInBackground(Void... arg0) {
				// TODO Auto-generated method stub
				if (!isCalculating){
					isCalculating = true;
					try {
						isAnisotropic = false;
						if(m_POIS.get(replaceTo)[5].equals("true"))
							isAnisotropic = true;
						accCost = new RasterLayer(RasterLayer.ICC);
						//this task take some time...
						//Toast.makeText(getApplicationContext(), "OK 1", Toast.LENGTH_LONG).show();
						long startTime = System.currentTimeMillis();
						(new Logger()).writeLog("PROC ==> Starting LCP calculation <==");
						accCost.initFromFile(m_POIS.get(replaceTo)[2], new File(path_accCost));
						long endTime = System.currentTimeMillis();
						endTime -= startTime;
						String cellsize = Integer.toString( (int)accCost.getWindowCellSize(0, 0));
						(new Logger()).writeLog("PROC_TIME ==> AccCost " + cellsize + "x" + cellsize +" loaded in: " + Long.toString(endTime) + " ms");
						//Toast.makeText(getApplicationContext(), "OK 2", Toast.LENGTH_LONG).show();
						
					} catch (Exception e) {
						// TODO Auto-generated catch block
						Toast.makeText(getApplicationContext(), "Problem occures while loading AccCost", Toast.LENGTH_LONG).show();
						e.printStackTrace();
						(new Logger()).writeLog("ERROR ==> Problem occures while loading AccCost");
					}
					isCalculating = false;
					return true;
				}
				
				return false;
			}
			
			@Override
			protected void onCancelled(){
				try {
					
				} catch (Throwable e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		} //end my AsyncTask
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item){
		final Dialog dialog;
		final Context ctx = this;
		Intent intent;
		
		switch(item.getItemId()){
		//button settings
		case R.id.action_settings:
			//creation of the new activity showing the settings menu
			intent = new Intent(this, SettingsActivity.class);
			intent.putExtra(SettingsActivity.DIST_METHOD, distMethod);
			intent.putExtra(SettingsActivity.K_FACTOR, factorK);
			this.startActivityForResult(intent, this.ACT_SETTINGS);
			break;
			
		//button to add a new destination --> create a new Cost Surface
		case R.id.action_newDest:
			intent = new Intent(this, PoiActivity.class);
			intent.putExtra(PoiActivity.DEST_LAT, touchLat);
			intent.putExtra(PoiActivity.DEST_LON, touchLon);
			this.startActivityForResult(intent, this.ACT_POI);
			break;
			
		case R.id.action_origin:
			intent = new Intent(this, OrigActivity.class);
			intent.putExtra("touchLat", touchLat);
			intent.putExtra("touchLon", touchLon);
			intent.putExtra("gpsLat", gpsLat);
			intent.putExtra("gpsLon", gpsLon);
			this.startActivityForResult(intent, this.ACT_ORIG);
			break;
			
		case R.id.action_destination:
			//define dialog with the list of possibles destinations
			CharSequence[] allDest = new CharSequence[m_POIS.size()];
			for(int ii= 0; ii < allDest.length; ii++)
				allDest[ii] = m_POIS.get(ii)[1];
			intent = new Intent(this, ListActivity.class);
			intent.putExtra(ListActivity.SURFACES_AVAILABLE, allDest);
			this.startActivityForResult(intent, this.ACT_LIST);
			break;
		default:
			break;
		}
		return super.onMenuItemSelected(featureId, item);
	}
	
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data){
		Bundle bundle;
		if (resultCode == Activity.RESULT_OK){
			bundle = data.getExtras();
			switch(requestCode){
			case ACT_SETTINGS:
				this.factorK = bundle.getDouble(SettingsActivity.K_FACTOR, 2.0);
				this.distMethod = bundle.getInt(SettingsActivity.DIST_METHOD, 0);
				//code to read configuration from file and folder here
				Toast.makeText(getApplicationContext(), Integer.toString(distMethod), Toast.LENGTH_LONG).show();
				break;
			case ACT_POI:
				lat = bundle.getDouble(PoiActivity.DEST_LAT);
				lon = bundle.getDouble(PoiActivity.DEST_LON);
				name_POI = bundle.getString(PoiActivity.NAME_POI);
				isAnisotropic = bundle.getBoolean(PoiActivity.TYPE_SURFACE);
				replaceTo = bundle.getInt(PoiActivity.REPLACE_TO);
				//code to calculate new AccCost surface
				MyCalcNewAccCost mCnaccCost = new MyCalcNewAccCost();
				mCnaccCost.execute();
				break;
				
			case ACT_ORIG:
				lat = bundle.getDouble(OrigActivity.ORIG_LAT);
				lon = bundle.getDouble(OrigActivity.ORIG_LON);
				//code to calculate "Least-Cost Path" here
				MyCalcLCP mLcp = new MyCalcLCP();
				mLcp.execute();
				myMapView.refreshDrawableState();
				break;
			case ACT_LIST:
				replaceTo = bundle.getInt(ListActivity.SURFACE);
				MyLoadAccCost mAccCost  = new MyLoadAccCost();
				mAccCost.execute();
				break;
			}
		}
	}

}
